package com.binioter.guideview;

import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.render.BlendMode;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

import java.io.IOException;
import java.io.InputStream;

/**
 * Created by binIoter
 *
 * @since 2021-04-19
 */
class MaskView extends ComponentContainer implements Component.DrawTask, Component.EstimateSizeListener, ComponentContainer.ArrangeListener {
    /**
     * 高亮区域
     */
    private final RectFloat mTargetRect = new RectFloat();
    /**
     * 蒙层区域
     */
    private final RectFloat mOverlayRect = new RectFloat();

    /**
     * 中间变量
     */
    private final RectFloat mChildTmpRect = new RectFloat();
    /**
     * 蒙层背景画笔
     */
    private Paint mFullingPaint;
    private int mPadding = 0;
    private int mPaddingLeft = 0;
    private int mPaddingTop = 0;
    private int mPaddingRight = 0;
    private int mPaddingBottom = 0;
    /**
     * 是否覆盖目标区域
     */
    private boolean mOverlayTarget = false;
    /**
     * 圆角大小
     */
    private int mCorner = 0;
    /**
     * 目标区域样式，默认为矩形
     */
    private int mStyle = viewComment.ROUNDRECT;
    /**
     * 挖空画笔
     */
    private Paint mEraser;
    /**
     * 橡皮擦Bitmap
     */
    private PixelMap mEraserBitmap;
    /**
     * 橡皮擦Cavas
     */
    private Canvas mEraserCanvas;

    private boolean ignoreRepadding;

    private int mInitHeight;
    private int mChangedHeight = 0;
    private boolean mFirstFlag = true;
    private int width;
    private int height;
    private Texture texture;
    private int num = 0;
    private int imaId;
    private Texture img;

    public void setImaId(int imaId) {
        this.imaId = imaId;
    }

    public void setText(String text) {
        this.text = text;
    }

    private String text = "";


    MaskView(Context context) {
        super(context);
        width = DensityUtils.getDeviceAttr(context).getAttributes().width;
        height = DensityUtils.getDeviceAttr(context).getAttributes().height;

        //蒙层区域
        mOverlayRect.left = 0;
        mOverlayRect.top = 0;
        mOverlayRect.right = width;
        mOverlayRect.bottom = height;

        //生成蒙层bitmap
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        options.editable = true;
        options.pixelFormat = PixelFormat.ARGB_8888;
        Size size = new Size(width, height);
        options.size = size;
        mEraserBitmap = PixelMap.create(options);

        //设置画布
        texture = new Texture(mEraserBitmap);
        mEraserCanvas = new Canvas(texture);

        mFullingPaint = new Paint();
        mEraser = new Paint();
        mEraser.setColor(Color.WHITE);

        //图形重叠时的处理方式，擦除效果
        mEraser.setBlendMode(BlendMode.CLEAR);

        //位图抗锯齿设置
        mEraser.setAntiAlias(true);
        if (num == 0) {
            num++;
            setEstimateSizeListener(this::onEstimateSize);
            setArrangeListener(this::onArrange);
            addDrawTask(this::onDraw);
        }
    }

    @Override
    public void release() {
        super.release();
        try {
            clearFocus();
            mEraserCanvas.setTexture(null);
            mEraserBitmap = null;
        } catch (Exception e) {
            e.fillInStackTrace();
        }
    }

    @Override
    public LayoutParams getLayoutConfig() {
        return new LayoutParams(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
    }

    private void horizontalChildPositionLayout(Component child, RectFloat rect, int targetParentPosition) {
        switch (targetParentPosition) {
            case LayoutParams.PARENT_START:
                rect.left = mTargetRect.left;
                rect.right = rect.left + child.getWidth();
                break;
            case LayoutParams.PARENT_CENTER:
                rect.left = (mTargetRect.getWidth() - child.getWidth()) / 2;
                rect.right = (mTargetRect.getWidth() + child.getWidth()) / 2;
                rect.shrink(mTargetRect.left, 0);
                break;
            case LayoutParams.PARENT_END:
                rect.right = mTargetRect.right;
                rect.left = rect.right - child.getWidth();
                break;
            default:
                break;
        }
    }

    private void verticalChildPositionLayout(Component child, RectFloat rect, int targetParentPosition) {
        switch (targetParentPosition) {
            case LayoutParams.PARENT_START:
                rect.top = mTargetRect.top;
                rect.bottom = rect.top + child.getHeight();
                break;
            case LayoutParams.PARENT_CENTER:
                rect.top = (mTargetRect.getWidth() - child.getHeight()) / 2;
                rect.bottom = (mTargetRect.getWidth() + child.getHeight()) / 2;

                rect.shrink(0, mTargetRect.top);
                break;
            case LayoutParams.PARENT_END:
                rect.bottom = mTargetRect.bottom;
                rect.top = mTargetRect.bottom - child.getHeight();
                break;
            default:
                break;
        }
    }

    private void resetOutPath() {
        resetPadding();
    }

    /**
     * 设置padding
     */
    private void resetPadding() {
        if (!ignoreRepadding) {
            if (mPadding != 0 && mPaddingLeft == 0) {
                double left = (double)mTargetRect.left;
                left -= mPadding;
                mTargetRect.left = (float) left;
            }
            if (mPadding != 0 && mPaddingTop == 0) {
                double top = (double)mTargetRect.top;
                top -= mPadding;
                mTargetRect.top = (float) top;
            }
            if (mPadding != 0 && mPaddingRight == 0) {
                double right = (double)mTargetRect.right;
                right += mPadding;
                mTargetRect.right = (float) right;
            }
            if (mPadding != 0 && mPaddingBottom == 0) {
                double bottom = (double)mTargetRect.bottom;
                bottom += mPadding;
                mTargetRect.bottom = (float) bottom;
            }
            if (mPaddingLeft != 0) {
                double left = (double)mTargetRect.left;
                left -= mPaddingLeft;
                mTargetRect.left = (float) left;
            }
            if (mPaddingTop != 0) {
                double top = (double)mTargetRect.top;
                top -= mPaddingTop;
                mTargetRect.top = (float) top;
            }
            if (mPaddingRight != 0) {
                double right = (double)mTargetRect.right;
                right += mPaddingRight;
                mTargetRect.right = (float) right;
            }
            if (mPaddingBottom != 0) {
                double bottom = (double)mTargetRect.bottom;
                bottom += mPaddingBottom;
                mTargetRect.bottom = (float) bottom;
            }
            ignoreRepadding = true;
        }
    }

    public void setTargetRect(Rect rect) {
        RectFloat rectFloat = new RectFloat();
        rectFloat.left = rect.left;
        rectFloat.right = rect.right;
        rectFloat.top = rect.top;
        rectFloat.bottom = rect.bottom;
        mTargetRect.fuse(rectFloat);
    }

    public void setFullingAlpha(int alpha) {
        mFullingPaint.setAlpha(alpha);
    }

    public void setFullingColor(int color) {
        mFullingPaint.setColor(Color.BLUE);
    }

    public void setHighTargetCorner(int corner) {
        this.mCorner = corner;
    }

    public void setHighTargetGraphStyle(int style) {
        this.mStyle = style;
    }

    public void setOverlayTarget(boolean isb) {
        mOverlayTarget = isb;
    }

    public void setPadding(int padding) {
        this.mPadding = padding;
    }

    public void setPaddingLeft(int paddingLeft) {
        this.mPaddingLeft = paddingLeft;
    }

    public void setPaddingTop(int paddingTop) {
        this.mPaddingTop = paddingTop;
    }

    public void setPaddingRight(int paddingRight) {
        this.mPaddingRight = paddingRight;
    }

    public void setPaddingBottom(int paddingBottom) {
        this.mPaddingBottom = paddingBottom;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        Component component1 = new Component(component.getContext());
        addComponent(component1);

        if (mChangedHeight != 0) {
            mTargetRect.shrink(0, mChangedHeight);
            mInitHeight = mInitHeight + mChangedHeight;
            mChangedHeight = 0;
        }
        texture.getPixelMap().writePixels(Color.TRANSPARENT.getValue());

        // 蒙版颜色
        mEraserCanvas.drawColor(Color.getIntColor("#80000000"), Canvas.PorterDuffMode.SRC);
        if (imaId != 0 || !text.equals("")) {
            Paint paint = new Paint();
            paint.setColor(Color.WHITE);
            paint.setTextSize(50);
            if (imaId != 0) {
                PixelMap pixelMap = getPixelMap(mContext, imaId);
                img = new Texture(pixelMap);
            }
            double isx = 0;
            if (mTargetRect.getWidth() > paint.measureText(text)) {
                // 如果区域大于文字  已区域的   中间
                isx = ((double)mTargetRect.right) / 2 - (double)paint.measureText(text) / 2;
            } else {
                // 从右边画
                isx = (double)mTargetRect.right - (double)paint.measureText(text);
            }
            mEraserCanvas.drawText(paint, text, (float) isx, (float)((double)mTargetRect.bottom + paint.getTextSize() + 40));
            if (imaId != 0) {
                mEraserCanvas.drawTexture((float)isx, (float)((double)mTargetRect.bottom + paint.getTextSize() + 40), img);
            }
        }
        if (!mOverlayTarget) {
            switch (mStyle) {
                case viewComment.CIRCLE:
                    mEraserCanvas.drawCircle(mTargetRect.getHorizontalCenter(), mTargetRect.getVerticalCenter(),
                            mTargetRect.getWidth() / 2, mEraser);
                    break;
                default:
                    mEraserCanvas.drawRoundRect(mTargetRect, mCorner, mCorner, mEraser);
                    break;
            }
        }
        canvas.drawTexture(0, 0, texture);
    }

    /*
     * onMeasure方法
     * */
    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int weigh = MeasureSpec.getSize(widthMeasureSpec);

        int heigh = MeasureSpec.getSize(heightMeasureSpec);
        if (mFirstFlag) {
            mInitHeight = heigh;
            mFirstFlag = false;
        }
        if (mInitHeight > heigh) {
            mChangedHeight = heigh - mInitHeight;
        } else if (mInitHeight < heigh) {
            mChangedHeight = heigh - mInitHeight;
        } else {
            mChangedHeight = 0;
        }
        setEstimatedSize(weigh, heigh);
        mOverlayRect.fuse(0, 0, weigh, heigh);
        resetOutPath();
        final int count = getChildCount();
        Component child;
        for (int i = 0; i < count; i++) {
            child = getComponentAt(i);
            if (child != null) {
                child.setComponentMinSize(widthMeasureSpec, heightMeasureSpec);
            }
        }
        return false;
    }

    @Override
    public boolean onArrange(int l, int t, int w, int h) {
        int count = getChildCount();
        Component child;
        for (int i = 0; i < count; i++) {
            child = getComponentAt(i);
            if (child == null) {
                continue;
            }
            LayoutConfig layoutConfig = child.getLayoutConfig();
            LayoutParams lp = new LayoutParams(layoutConfig.width, layoutConfig.height);
            if (lp == null) {
                continue;
            }
            switch (lp.targetAnchor) {
                case LayoutParams.ANCHOR_LEFT: //左
                    mChildTmpRect.right = mTargetRect.left;
                    mChildTmpRect.left = (float)((double)mChildTmpRect.right - (double)child.getWidth());
                    verticalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
                    break;
                case LayoutParams.ANCHOR_TOP://上
                    mChildTmpRect.bottom = mTargetRect.top;
                    mChildTmpRect.top = (float)((double)mChildTmpRect.bottom - child.getHeight());
                    horizontalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
                    break;
                case LayoutParams.ANCHOR_RIGHT://右
                    mChildTmpRect.left = mTargetRect.right;
                    mChildTmpRect.right = (float)((double)mChildTmpRect.left + child.getWidth());
                    verticalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
                    break;
                case LayoutParams.ANCHOR_BOTTOM://下
                    mChildTmpRect.top = mTargetRect.bottom;
                    mChildTmpRect.bottom = (float)((double)mChildTmpRect.top + child.getHeight());
                    horizontalChildPositionLayout(child, mChildTmpRect, lp.targetParentPosition);
                    break;
                case LayoutParams.ANCHOR_OVER://中心
                    mChildTmpRect.left = ((int) ((double)mTargetRect.getWidth() - child.getWidth())) >> 1;
                    mChildTmpRect.top = ((int) ((double)mTargetRect.getHeight() - child.getHeight())) >> 1;
                    mChildTmpRect.right = ((int) ((double)mTargetRect.getWidth() + child.getWidth())) >> 1;
                    mChildTmpRect.bottom = ((int)((double) mTargetRect.getHeight() + child.getHeight())) >> 1;
                    mChildTmpRect.fuse(mTargetRect.left, mTargetRect.top);
                    break;
                default:
                    break;
            }
            float density = DisplayManager.getInstance().getDefaultDisplay(mContext).get().getAttributes().densityPixels;
            mChildTmpRect.translate((int) ((double)density * (double)lp.offsetX + (double)0.5f),
                    (int) ((double)density * (double)lp.offsetY + (double)0.5f));
            child.arrange((int) mChildTmpRect.left, (int) mChildTmpRect.top, (int) mChildTmpRect.right,
                    (int) mChildTmpRect.bottom);
        }
        return false;
    }

    static class LayoutParams extends LayoutConfig {

        public static final int ANCHOR_LEFT = 0x01;
        public static final int ANCHOR_TOP = 0x02;
        public static final int ANCHOR_RIGHT = 0x03;
        public static final int ANCHOR_BOTTOM = 0x04;
        public static final int ANCHOR_OVER = 0x05;

        public static final int PARENT_START = 0x10;
        public static final int PARENT_CENTER = 0x20;
        public static final int PARENT_END = 0x30;

        public int targetAnchor = ANCHOR_BOTTOM;
        public int targetParentPosition = PARENT_CENTER;
        public int offsetX = 0;
        public int offsetY = 0;

        LayoutParams(int width, int height) {
            super(width, height);
        }
    }

    /**
     * 获取转换的pixelMap
     *
     * @param context    上下文
     * @param drawableId 图片资源
     * @return 返回null
     */

    public static PixelMap getPixelMap(Context context, int drawableId) {
        InputStream drawableInputStream = null;
        try {
            drawableInputStream = context.getResourceManager().getResource(drawableId);
            ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
            sourceOptions.formatHint = "image/png";
            ImageSource imageSource = ImageSource.create(drawableInputStream, sourceOptions);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            decodingOptions.desiredSize = new Size(0, 0);
            decodingOptions.desiredRegion = new ohos.media.image.common.Rect(0, 0, 0, 0);
            decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
            PixelMap pixelMap = imageSource.createPixelmap(decodingOptions);
            return pixelMap;
        } catch (IOException | NotExistException e) {
            e.fillInStackTrace();
        } finally {
            try {
                if (drawableInputStream != null) {
                    drawableInputStream.close();
                }
            } catch (IOException e) {
                e.fillInStackTrace();
            }
        }
        return null;
    }
}
